home *** CD-ROM | disk | FTP | other *** search
/ TeX 1995 July / TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO / systems / atari / birkhahn-metafont-packed-disks / mf27-2_2e-disk2.zoo / inputs / pandora.lzs / PANDOR.MF < prev    next >
Text File  |  1991-08-15  |  34KB  |  771 lines

  1. %*****************************************************************************
  2. %        Copyright (c) 1989 by N. N. Billawala
  3. %*****************************************************************************
  4.  
  5.  
  6. % pandor.mf  a base file which contains the macros used for creating Pandora
  7.  
  8.  
  9. %*****MAJOR CHARACTER PART MACROS**************************************
  10.  
  11.  
  12. boolean its_a_leftserif;                % in horizontal serif macro 
  13.  
  14. vardef full_serif_points@#(expr A,B,Bl,Br,leftlength,rightlength)=
  15.   min_limit(join_radius)(.5serif_thickness);
  16.   (z1-B)=whatever*(A@#-B@#);            % makes center ref line
  17.   (z1l-Bl)=whatever*(A@#-B@#);          % makes parallel ref line on left
  18.   (z1r-Br)=whatever*(A@#-B@#);          % makes parallel ref line on right
  19.  
  20.   y2=y2l=y2r=ypart A;                   % base of serif 
  21.   y1=y1l=y1r=y3=y4=ypart A if ypart A>ypart B:-else:+fi serif_thickness;
  22.                                         % puts serif_thickness between A and B
  23.   x5=x2=.5[x1l,x1r];                    % puts entasis at mid-base and makes it
  24.   y5=entasis[y2l,y1l];                  %   a proportion of the serif_thickness
  25.  
  26.   if its_a_leftserif:x3=x2l=x1l-round(leftlength+serif_constant_amt); 
  27.    else:x4=x2r=x1r+round(rightlength+serif_constant_amt); fi
  28. enddef;                      
  29.  
  30. vardef leftserif@#(expr A,B,Bl,Br,alength)=its_a_leftserif:=true;  % left serif
  31.   save x,y,p; path p[]; 
  32.   full_serif_points@#(A,B,Bl,Br,alength,0);                
  33.   p0:=Bl{z1l-Bl} if ctrls:..controls(onstem[z1l,Bl])and(onbase[z1l,z3])..
  34.      else:...fi {z3-z1l}z3;                        % the bracket curve
  35.   if midbracket_pull<>0: 
  36.     z3'l=z1l; pos3'(alength+5pt,.5[angle(B-A),if ypart A>ypart B:-fi 180]);
  37.     z8'=p0 intersectionpoint (z3'l--z3'r);         % z3'l--z3'r bisects bracket
  38.     z8=(midbracket_pull-eps)[z8',z1l];fi           % bracket pulled in at z8
  39.   if ypart A>ypart B:reverse fi   
  40.   ((if midbracket_pull=0:p0 else:Bl{z1l-Bl}...z8...{z3-z1l}z3 fi 
  41.    if softpath:)softjoin(z3--z2l)softjoin(else:--fi z2l..z5{right}))
  42. enddef;
  43.  
  44. vardef rightserif@#(expr A,B,Bl,Br,alength)=its_a_leftserif:=false;% right serif
  45.   save x,y,p; path p[]; 
  46.   full_serif_points@#(A,B,Bl,Br,0,alength);
  47.   p4:=z4{z1r-z4} if ctrls:..controls(onbase[z1r,z4])and(onstem[z1r,Br])..
  48.      else:...fi {Br-z1r}Br;                        % the bracket curve
  49.   if midbracket_pull<>0:
  50.     z4'l=z1r; pos4'(alength+5pt,.5[angle(B-A),0]);
  51.     z9'=p4 intersectionpoint (z4'l--z4'r);         % z4'l--z4'r bisects bracket
  52.     z9=(midbracket_pull-eps)[z9',z1r];fi           % bracket pulled in at z9
  53.   if ypart A>ypart B:reverse fi
  54.    ((z5{right}..z2r if softpath:)softjoin(z2r--z4)softjoin(else:--fi
  55.     if midbracket_pull=0:p4 else:z4{z1r-z4}...z9...{Br-z1r}Br fi))
  56. enddef;
  57.                             
  58. vardef fullserif@#(expr A,B,Bl,Br,leftlength,rightlength)=         % full serif
  59.   save x,y,p; path p[];
  60.   p1=rightserif(A,B,Bl,Br,rightlength); p2=leftserif(A,B,Bl,Br,leftlength);
  61.   if ypart A>ypart B:(p1--p2)else:(p2--p1)fi
  62. enddef;
  63.  
  64.  
  65.  
  66. vardef terminalserif@#(expr A,B,Bl,Br,tip_length,base_angle)suffix$=
  67.  
  68.   save x,y,join_radius,aleft,atop,arc,ball,heel,midbracket_point,tip,p; 
  69.   boolean aleft,atop; pair arc,ball,heel,midbracket_point,tip; path p[];
  70.   aleft=(str@#="l"); atop=(ypart A>ypart B);
  71.  
  72.   heel- if aleft:Br else:Bl fi =whatever*(A-B);  
  73.   heel=A+(whatever,0)rotated(if not aleft:180+ fi base_angle);
  74.   ball- if aleft:Bl else:Br fi =whatever*(A-B); ball=whatever[heel,A]; 
  75.  
  76.   z0=A if atop:-else:+fi(0,terminal_thickness) rotated base_angle;
  77.                     % z0 added for cases of small terminal_thickness and length
  78.   z2=whatever[ball,if aleft:Bl else:Br fi]; (z0-z2)=whatever*(ball-A);
  79.                     % terminal_thickness and stem intersection when no bracket
  80.   z1=z2+(tip_length+serif_constant_amt,0)rotated angle(ball-A);
  81.                     % z1 is an inner tip point
  82.   tip=whatever[heel,ball]; z1-tip=whatever*(z0-A);
  83.                     % places tip on base by an amount past the stem
  84.   z3=heel if str$="soft":+(terminal_softness+1,0)rotated angle(tip-heel)fi;
  85.   arc=.5[z3,tip]+(terminal_entasis*terminal_thickness,0)rotated angle(B-A);
  86.  
  87.   if aleft:z5=Bl; z6=Br; else:z5=Br; z6=Bl;fi
  88.   p1=z5{ball-z5} if ctrls:
  89.        ..controls(onstem[z2,z5])and(onbase[z2,(-eps)[z1,tip]])..
  90.          else:...fi {z1-z2}(-eps)[z1,tip]--z1;
  91.   join_radius:=min(terminal_softness,abs(heel-z3),.5abs(heel-z6));
  92.   p2=(arc{heel-tip}...z3{heel-tip}...{heel-tip}heel 
  93.      if str$="soft":)softjoin(heel fi --z6);
  94.   min_limit(join_radius)(.5terminal_thickness);
  95.  
  96.   if midbracket_pull<>0:
  97.     bisecting_angle:=if aleft and(sign(angle(B-A))<>sign(angle(ball-A))):
  98.                     180+fi .5[angle(B-A),angle(ball-A)];
  99.                     % this angle bisects the inner angle/area of the bracket
  100.     z4=z2+(tip_length+5pt+serif_constant_amt,0)rotated bisecting_angle;
  101.                     % sets point z4 for a reference path along bisecting angle
  102.     midbracket_point=(z2--z4)intersectionpoint p1;
  103.                     % midbracket_point intersects the reference path along the 
  104.                     % bisecting angle and the reference path of the bracket
  105.     z9=(midbracket_pull-eps)[midbracket_point,z2];   
  106.                     % the final path goes through z9, which gives the amount of
  107.                     % "pull" toward the point where the stem meets the terminal
  108.     fi              % base with no bracketing
  109.  
  110.   if atop=aleft:reverse fi
  111.    ((if midbracket_pull=0:p1
  112.       else:z5{ball-z5}...z9...{z1-z2}(-eps)[z1,z2]--z1 fi
  113.     if softpath:)softjoin(z1--tip)softjoin(else:--fi
  114.     tip..arc{heel-tip}--p2))
  115. enddef;
  116.     
  117.  
  118. vardef arm@#                                 % uses @#strings of tl,tr,bl,br
  119.   (expr heel,inner_ref,outer_ref,tip_length,tipthickness,base_angle)suffix$=
  120.  
  121.   save x,y,innertip,outertip,toward,control_point,tip_direction,midbase,section;
  122.   pair innertip,outertip,toward,control_point,tip_direction,midbase; 
  123.   path section[];             % separate parts of path for different join_radii
  124.   save_bool(atop)=((str@#="tr")or(str@#="tl"));
  125.   save_bool(curvedarm)=(atop and (ypart outer_ref>ypart heel))  or 
  126.                        ((not atop) and (ypart outer_ref<ypart heel)); 
  127.  
  128.   toward=(xpart heel-xpart outer_ref,0);       % direction going toward the heel
  129.   tip_direction=dir(base_angle if atop:+180 fi-oblique); 
  130.   z0=whatever[heel,heel+eps*tip_direction]; y0=ypart inner_ref;
  131.   outertip=if not curvedarm:z0+(tip_length,0) 
  132.     else:heel+(max(tip_length,abs(z0-heel)),0) fi  rotated angle tip_direction;
  133.   midbase=.5[outertip,heel];
  134.   innertip=outertip+tipthickness*           
  135.            dir(base_angle+if((str@#="tl")or(str@#="bl")):- else:+fi 90-oblique);
  136.   control_point-innertip=whatever*(heel-outertip);
  137.   control_point=whatever[inner_ref,z0];
  138.   save_num(join_radius)=
  139.     min(.5abs(outertip-heel),abs(heel-outer_ref),arm_softness);
  140.   section1=(midbase--heel)softjoin(heel...outer_ref{-toward});
  141.   section2=
  142.    (inner_ref{toward}
  143.       if curvedarm:...
  144.           if abs(innertip-control_point)>abs(inner_ref-control_point):
  145.           if atop:{downward} else:{upward} fi fi
  146.         else:..controls(onstem[control_point,inner_ref])and
  147.                        (onbase[control_point,innertip])..{outertip-heel} fi 
  148.     innertip if softpath:)softjoin(innertip--outertip)softjoin( else:--fi
  149.     outertip--midbase);
  150.  
  151.   if ((str@#="tl")or(str@#="br")):reverse fi  (section2--section1)
  152. enddef;
  153.  
  154. vardef bulb@#                                                      % like arm
  155.  (expr heel,inner_ref,outer_ref,tip_length,tipthickness,base_angle)suffix$=
  156.  save x,y,athickness,alength,bulb_taper_angle; z0=heel;
  157.  if bulbs: save_bool(softpath)=true; fi 
  158.  if bulb_taper:athickness=1; bulb_thickness:=athickness;
  159.     bulb_taper_angle=base_angle 
  160.       if((str@#="tr")or(str@#="bl")):-else:+fi taper_angle;
  161.     alength=if (c_and_s.lc<>0)or(c_and_s.uc<>0):max else:min fi
  162.             (abs(ypart outer_ref-ypart inner_ref),tip_length);
  163.   else:athickness=tipthickness;alength=tip_length;bulb_taper_angle=base_angle;fi
  164.  arm@#(z0,inner_ref,outer_ref,alength,athickness,bulb_taper_angle)$
  165. enddef;
  166.  
  167.  
  168. vardef shortarm@#(expr AA,BB,CC,D,E,F)suffix$=  % short form inspired by DEK
  169.   save x,y,GG,HH,II,JJ,KK,LL,M; pair GG,HH,II,JJ,KK,LL; path M[];
  170.   save_bool(N)=((str@#="tr")or(str@#="tl"));
  171.   save_bool(O)=(N and(ypart CC>ypart AA))or((not N)and(ypart CC<ypart AA));
  172.   II=(xpart AA-xpart CC,0);       % direction going II the AA
  173.   KK=dir(F if N:+180 fi-oblique); 
  174.   z0=whatever[AA,AA+eps*KK]; y0=ypart BB;
  175.   HH=if not O:z0+(D,0)else:AA+(max(D,abs(z0-AA)),0)rotated angle KK;
  176.   LL=.5[HH,AA];
  177.   GG=HH+E*dir(F+if((str@#="tl")or(str@#="bl")):- else:+fi 90-oblique);
  178.   JJ-GG=whatever*(AA-HH); JJ=whatever[BB,z0];
  179.   join_radius:=min(.5abs(HH-AA),abs(AA-CC),arm_softness);
  180.   M1=(LL--AA)softjoin(AA...CC{-II});
  181.   min_limit(join_radius)(.5E);
  182.   M2=(BB{II} if O:...if abs(GG-JJ)>abs(BB-JJ):if N:{downward}else:{upward} fi fi
  183.         else:..controls(onstem[JJ,BB])and(onbase[JJ,GG])..{HH-AA} fi 
  184.     GG if softpath:)softjoin(GG--HH)softjoin( else:-- fi HH--LL);
  185.   if ((str@#="tl")or(str@#="br")):reverse fi  (M2--M1)
  186. enddef;
  187.  
  188.  
  189.  
  190.  
  191. % limiting directions for the joining point of the arch to the assumed stem
  192.  
  193. vardef archlimit@#(expr p)= % limits dir at point 1 of path upward or downward
  194.  save a,b; pair b; b=(direction 1 of p); a=angle(b)+oblique; 
  195.    if (tr and((a<-180)or(-90<a)))or(tl and((a<-90)or(0<a))):downward
  196.     elseif (bl and((a<0)or(90<a)))or(br and((a<90)or(180<a))):upward  
  197.     else: b fi
  198.  enddef;
  199. vardef neg_archlimit@#(expr p)=dir(180+angle(archlimit@#(p))) enddef;
  200.  
  201. vardef arch@#(expr inner_tip_pt,yy,inner_stem_pt,outer_stem_pt)suffix$=
  202.   save x,y,tl,bl,tr,br,pp; boolean tl,bl,tr,br; path pp[];
  203.   tl=(str@#="tl"); tr=(str@#="tr"); bl=(str@#="bl"); br=(str@#="br");
  204.   save_bool(ontop)=tl or tr;
  205.   save_pair(stem_dir)=if ontop:upward else:downward fi;    % joining dir at stem
  206.   save_pair(toward)=(xpart(inner_tip_pt-inner_stem_pt),0); % dir right or left
  207.   pickup pencircle scaled minimum_linethickness;
  208.  
  209.   y0r=yy;                                       % connects extreme y-value
  210.   pos0(arch_thickness$,if ontop:+ else:-fi 90); %   to reference pts
  211.   good_x_for(0)(inner_tip_pt,inner_stem_pt,arch_reference)a;
  212.   z1l=inner_tip_pt;                             % placement of the "tip" of 
  213.   pos1(arch_tip$,if ontop:+ else:-fi90-oblique);%   the arch 
  214.   y2l=y0l; y2r=y0r;                             % z2l/z2r are actual arch points
  215.   good_x_for(2l)(inner_tip_pt,z0l,arch_inner_amt)b; 
  216.    if abs(x0l-x2l)>.5*arch_thickness$:x2l:=x0l 
  217.     if tl or bl:+else:-fi .5*arch_thickness$;fi
  218.   onaline(0,2l)(2r);            
  219.   onaline(1l,1r)(11); y11=if ontop:min else:max fi (.75[y0l,y0r],y1r);
  220.   if (tr or br):rt else:lft fi z10=.5[inner_tip_pt,z11];
  221.  
  222.   pp0=z0r{toward}...z1r;                        % ref paths for direction limits
  223.   pp1=z0l{toward}...z1l;      
  224.   pp2=z0{toward}...z1;
  225.   pp3=outer_stem_pt{stem_dir} o_t z2r{toward}...z11{archlimit@#(pp0)}--
  226.       inner_tip_pt{neg_archlimit@#(pp1)}...z2l{-toward} o_t 
  227.       inner_stem_pt{-stem_dir};
  228.   if ensure_min_archthickness:                     % path ensures min thickness
  229.     for n:=1,2:draw z0{toward}...z10{archlimit@#(pp2)};endfor   fi
  230.  
  231.   if (tr or br)<>ontop:reverse fi pp3
  232. enddef; 
  233.  
  234.  
  235.  
  236. vardef outer_juncture_path@#(expr arch_path,stem_path,atime)=     % for tr_bl
  237.   save x,y,t,tl,bl,tr,br,atop,aleft,pp,angle_limit;  
  238.   boolean tl,bl,tr,br,atop,aleft; path pp[];
  239.   tl=(str@#="tl"); tr=(str@#="tr"); bl=(str@#="bl"); br=(str@#="br");  
  240.   atop=tl or tr;  aleft=tl or bl;
  241.   if softjuncture=false:save join_radius; join_radius:=eps;fi
  242.  
  243.   z10=point atime of arch_path; 
  244.   z11=point (atime-1) of arch_path;
  245.   z12=z10+(eps,0)rotated angle(z10-precontrol atime of arch_path);
  246.   pp1=subpath (0,atime) of arch_path--z12;
  247.   z1=pp1 intersectionpoint stem_path;
  248.   (t1,t2)=pp1 intersectiontimes stem_path;
  249.   z2=z1+(juncture_opening,0)rotated(if aleft:180 else:0 fi-oblique);
  250.   angle_limit1=max(if atop:0,else:-179,-fi 90-oblique-stemcut_angle);
  251.   z3=z2 if juncture_opening>0:+(abs(z11-z10)+2,0)rotated angle_limit1 fi;
  252.   z4=(z2--z3) intersectionpoint reverse stem_path;
  253.   (t3,t4)=(z2--z3) intersectiontimes reverse stem_path;
  254.   (t5,t6)=z4 intersectiontimes stem_path;
  255.  
  256.   if archcut_angle<>0:
  257.      angle_limit2=if tl or br:max else:min fi 
  258.       (angle(z11-z10),angle(precontrol atime of arch_path-z10)-archcut_angle);
  259.      z5=z1+(abs(z11-z10)+2,0)rotated angle_limit2;
  260.      z6=(z5--z1) intersectionpoint pp1;    
  261.      (t7,t8)=(z5--z1) intersectiontimes pp1; 
  262.      (subpath(0,t8)of arch_path soften(z6,z1,z2,z4)       % indent into arch 
  263.   else:(subpath(0,t1)of arch_path soften(z1,z2,z4)        % indent into stem 
  264.   fi    (subpath(t4,0)of reverse stem_path))
  265. enddef; 
  266.  
  267.  
  268. % Only used in the lower case characters
  269.  
  270. vardef bowl@#(expr major_tip,yy,minor_tip,yyy,inner_bowl,outer_bowl)=
  271.  save arch_thickness,arch_tip,arch_reference,arch_inner_amt;
  272.  save major,minor; path major,minor;
  273.   arch_thickness.lc:=   minor_curve.lc;
  274.   arch_tip.lc:=         minor_bowl_tip.lc;
  275.   arch_reference:=      minor_bowl_reference;
  276.   arch_inner_amt:=      minor_bowl_inner_amt;
  277.    minor=arch if str@#="r":br else:tl fi(minor_tip,yyy,inner_bowl,outer_bowl)lc;
  278.   arch_thickness.lc:=   major_curve.lc;
  279.   arch_tip.lc:=            major_bowl_tip.lc;
  280.   arch_reference:=      major_bowl_reference;
  281.   arch_inner_amt:=      major_bowl_inner_amt;
  282.    major=arch if str@#="r":tr else:bl fi (major_tip,yy,inner_bowl,outer_bowl)lc;
  283.   major--minor
  284. enddef;
  285.  
  286. vardef bowl_counter(expr bowlpath)=      % returns the counter of a bowl path
  287.   save x,y;
  288.   z1=point 3 of bowlpath; z2=point 8 of bowlpath; z3=.5[z1,z2];
  289.   min_limit(join_radius)(.5*abs(z1-z2));
  290.   if softpath:(z3--z1)softjoin(z1--subpath(3,8)of bowlpath--z2)softjoin(z2--z3)
  291.    else:subpath(3,8)of bowlpath
  292.    fi
  293. enddef;
  294. vardef outer_bowlpath(expr p)=subpath(9,11)of p--subpath(0,2)of p enddef;  
  295.                           % return the major and minor outer paths of a bowl
  296.  
  297.  
  298. vardef circular_shape(expr ytop,ybot,xleft,xright,topstroke,sidestroke)=
  299.   save x,y,amt,ref; path ref[],ref[]';    
  300.   top y1r=ytop;  bot y1l=top y1r-topstroke;  
  301.   bot y3r=ybot;  top y3l=bot y3r+topstroke;  
  302.   lft z2r=(xleft,(1-v_stress)*h);    rt z2l=(lft x2r+sidestroke,(1-v_stress)*h);
  303.   rt z4r=(xright,v_stress*h);        lft z4l=(rt x4r-sidestroke,v_stress*h);  
  304.   good_x_for(1r)(z2r,z4r,h_stress)a;     good_x_for(1l)(z2l,z4l,(1-h_stress))b;
  305.   good_x_for(3r)(z2r,z4r,(1-h_stress))c; good_x_for(3l)(z2l,z4l,h_stress)d; 
  306.   z1=.5[z1l,z1r]; amt1=.5*abs(y1r-y1l);  
  307.   z3=.5[z3l,z3r]; amt3=.5*abs(y3r-y3l);
  308.   x1r:=inlimit(x1r)(x1-amt1,x1+amt1);  x1l:=inlimit(x1l)(x1-amt1,x1+amt1); 
  309.   x3r:=inlimit(x3r)(x3-amt3,x3+amt3);  x3l:=inlimit(x3l)(x3-amt3,x3+amt3);
  310.   ref1=z1r{left} o_t_c z2r{downward} o_t_c z3r{right} o_t_c 
  311.        z4r{upward} o_t_c cycle;
  312.   ref1'=z1l{left} i_t z2l{downward} i_t z3l{right} i_t z4l{upward} i_t cycle;
  313.  
  314.   if mode<>proof:fill ref1; unfill ref1'; 
  315.    else:pickup pencircle; draw ref1; draw ref1'; fi
  316. enddef;
  317.  
  318. def o_t=..tension atleast circ1.. enddef;    % outer curve tensions
  319. def i_t=..tension atleast circ2.. enddef;    % inner curve tensions
  320. def o_t_c=..tension atleast circ3.. enddef;  % outer circular_shape tensions
  321.  
  322.     
  323. %***** SOME ACCENT AND PUNCTUATION CHARACTER PART MACROS *****************
  324. %*****
  325. % The dot macro specifies a round path of diameter <size> to be placed from
  326. %   a reference point. 
  327. % Note that this dot does not slant with any obliqueness.
  328. % tension given the same as that for the circular shapes, since the actual
  329. %   "roundness" of the dot isn't very important; more important is that there
  330. %   is a mark there for distinguishing the character.
  331. % Used mostly in punctuation and accent characters
  332.  
  333. vardef dot@#(expr ref_pt,size)=
  334.   save x,y;
  335.       if str@#="b":z1l=ref_pt;          % dot placed above reference point
  336.   elseif str@#="t":z1r=ref_pt;          % dot placed below reference point 
  337.   elseif str@#="l":z2l=ref_pt;          % dot placed to right of reference point
  338.   elseif str@#="r":z2r=ref_pt;          % dot placed to left of reference point 
  339.               else:z1=ref_pt;  fi       % reference point is in center of dot
  340.   z2=z1; pos1(size,90); pos2(size,0);
  341.   z1r{left} o_t z2l{down} o_t z1l{right} o_t z2r{up} o_t cycle 
  342. enddef;
  343.  
  344.  
  345. %*****
  346.  
  347. % The prime_accent macro makes a four-sided polygon. 
  348. % It assumes that the top end is as thick or thicker than the bottom 
  349. %   end and rounds the thicker end.
  350. % Theta is the angle at the ends; flattened in bold chars,
  351. %   but theta could be an arbitrary value.
  352. % Used in grave/acute/long Hungarian accents
  353.  
  354. vardef prime_accent(expr top_pt,bot_pt,top_thickness,bot_thickness)=
  355.   save x,y,theta,adjustment;
  356.   z1=top_pt; z3=bot_pt;
  357.   if y3=y1: x1:=x1+eps; fi      % keeps from division by 0 error on next line
  358.   if bold:theta=0;adjustment=1/cosd (angle(z3-z1)+90);
  359.     else:theta=angle(z3-z1)+90; adjustment=1;fi
  360.   pos1(top_thickness*adjustment,theta);
  361.   pos3(bot_thickness*adjustment,theta);
  362.   z2r=z1r+(min(.5top_thickness,.5*abs(z3-z1)),0)rotated angle(z3r-z1r);
  363.   z2l=z1l+(min(.5top_thickness,.5*abs(z3-z1)),0)rotated angle(z3l-z1l);
  364.   onaline(1l,3l)(6l,7l);
  365.   onaline(1r,3r)(6r,7r); 
  366.   if x1>x3:y6l=y1r; y7r=y3l; else:y6r=y1l; y7l=y3r; fi
  367.   if realsoft_accents:
  368.      (z2r{z1r-z3r}...z1{z1l-z1r}...z2l{z3l-z1l} soften(z3l,z3r) z2r)--cycle
  369.     elseif x1>x3:z6l--z3l--z7r--z1r--cycle
  370.     else:z1l--z7l--z3r--z6r--cycle     fi
  371. enddef;
  372.  
  373. %*****
  374.         
  375. % The comma macro makes a dot-like figure with a tail.
  376. % The reference point is placed in the center of the <head> or <dot part>.
  377. % The <size> is the diameter of the <head>.
  378. % The tail extends past the head by <tail_length>. 
  379. % The thickness at the tip of the tail is <tail_tip>.
  380. % The <tail_placement> positions the tail_tip in relation to the head.
  381. % And the <comma_dot_indent> affects the transition from tail_tip to head.
  382. % Used in comma/semi-colon/left and right, single and double quotes
  383.  
  384. vardef comma(expr pt,size,tail_length,tail_tip,tail_placement)=
  385.   save x,y,ref; path ref;
  386.   save_num(tail)=if prime:.5 else:tail_placement fi;
  387.   z1=z2=pt;  pos1(size,90-oblique);  pos2(size,0-oblique);
  388.   good_x_for(3)(z2l,z2r,comma_dot_indent)a; y3=y1l;
  389.   z4=(tail[x2l,x2r],y1l-tail_length) rotatedaround (pt,-oblique);
  390.   ref=pt{downward}...z4;
  391.   pos4(tail_tip,angle(direction 1 of ref)+90);
  392.  
  393.   if prime:z1r{left} o_t {downward}z2l--z4l--z4r--z2r{upward}...cycle
  394.      else:z1r{left} o_t z2l{downward} o_t z3...z4l{direction 1 of ref}-- 
  395.           z4r{-direction 1 of ref}...z2r{upward}...cycle     fi
  396. enddef;
  397.  
  398. % *****
  399.  
  400. % The arrowhead macro makes an arrowhead which is then rotated around its tip
  401. % point to the desired direction. 
  402. % It points when @#=t:up,@#=b:down,@#=r:right,@#=l:left.
  403. % The head_width is the widest (horizontal) span of the arrowhead.
  404. % The head_depth is the perpendicular distance from the tip to widest part
  405.  
  406. vardef arrow@#(expr tip,head_width,head_depth)=
  407.  save x,y,p; path p[];
  408.  z1=tip;
  409.  y2=y3=y1+head_depth; 
  410.  round x1=x2+.5head_width=x3-.5head_width;    
  411.  z4=(x2,y1-1.5head_depth);
  412.  z5=(x3,y4);
  413.  penpos1(head_thickness,90); 
  414.  penpos2(head_thickness,angle(z2-z1)-90);
  415.  penpos3(head_thickness,angle(z3-z1)+90);
  416.  p1=z1l--z2l--z2r--z1r--z1r-(eps,0)--z3r--z3l--z1l-(eps,0)--cycle;
  417.  p2=z1l--z2l--z4--z5--z3l--z1l--cycle;
  418.  save_num(turn)=if str@#="b":0-oblique elseif str@#="r":90 
  419.                  elseif str@#="t":180-oblique elseif str@#="l":270 fi;
  420.  fill p1 rotatedaround (tip,turn); unfill p2 rotatedaround (tip,turn);
  421. enddef; 
  422.  
  423.  
  424. %*** SHOW_CHARACTER macros ***********************************************
  425.  
  426. % These macros show the characters for different stages of development.
  427. % <fill_all>                   fill p[1-4]     unfill p'[1-4]
  428. % <draw_outlines>              draw p[1-4]     draw   p'[1-4]
  429. % <outline_and_fill>           does <draw_outlines> and <fill_all> shifted
  430. % <draw_with_reference_paths>  does <draw_outlines> and draw ref[1-6]
  431. % <openit> fixes size of terminalscreen window (altered from plain.mf)
  432. % <makebox> makes a reference box for screen/proof chars (altered from plain.mf)
  433. % <showpoints> shows point positions on screen while working on char
  434.  
  435. def fill_all= 
  436.   for n=1 upto 6:if known p[n]:fill p[n];fi if known p[n]':unfill p[n]';fi 
  437.    endfor enddef;           
  438. def draw_outlines=  pickup pencircle;
  439.   for n=1 upto 6:if known p[n]:draw p[n];fi if known p[n]':draw p[n]';fi endfor 
  440.   enddef;
  441. def outline_and_fill= pickup pencircle;
  442.   for n=1 upto 6: 
  443.   if known p[n]: draw p[n]; fill p[n] shifted (0,-(h+d+100)); fi
  444.   if known p[n]':draw p[n]'; unfill p[n]' shifted (0,-(h+d+100)); fi  
  445.   endfor enddef;
  446. def draw_with_reference_paths= 
  447.   draw_outlines;
  448.   pickup pencircle scaled .15pt; 
  449.   for n=1 upto 6:if known p[n]: draw ref[n]; fi endfor  
  450.   enddef;
  451.  
  452. def openit = openwindow currentwindow   % fixes size of terminalscreen window
  453.  from (0,0) to (1.5screen_rows,screen_cols) at (-100,300) enddef;
  454.  
  455. def makebox(text rule)= % makes a reference box for screen and proof characters    
  456.  for y=0,h.o_,-d.o_: rule((l,y),(r,y));  endfor % horizontals
  457.  for x=l,r:    rule((x,-d.o_),(x,h.o_)); endfor % outer verticals
  458.  for x=0,wsaved: rule((x,0),(x,.2h.o_)); endfor % inner verticals
  459.  if charic<>0: rule((wsaved+charic*hppp,h.o_),(wsaved+charic*hppp,.5h.o_));fi
  460. enddef;
  461.  
  462. def showpoints(text t)= % Shows point positions on screen while working on char
  463.  if mode=proof:pickup pencircle scaled 3;
  464.  forsuffixes $:=t:forsuffixes s:=l,,r:if known z$.s:draw z$s;fi endfor endfor 
  465.  pickup pencircle scaled 1; penlabels(t); fi
  466. enddef;
  467.  
  468.  
  469. %*****EXTRA***********************************************************
  470.  
  471.  
  472. %*****VARIATIONS on some PLAIN.MF macros
  473.   
  474. %***** 
  475. % This allows a selection of chars to be tested, w/o losing memory to defs
  476. % An extra line [iff OK "<character>":] must be added before each char
  477.  
  478. let semi_ = ;; let colon_ = :; let endchar_ = endchar;
  479. def iff expr b = if b:let next_=use_it else:let next_=lose_it fi; next_ enddef;
  480. def use_it = let : = restore_colon; enddef;
  481. def restore_colon = let : = colon_; enddef;
  482. def lose_it = let endchar=fi; let ;=restore_endchar semi_ if false enddef;
  483. def restore_endchar=let ;=semi_; let endchar=endchar_; enddef;
  484. def always_iff expr b = use_it enddef;
  485. boolean wanted[];
  486.  
  487. % To use this bit of magic, include the following commented-out lines
  488.  % for x:="I":
  489.  %   wanted[byte x]:=true; endfor 
  490.           % this allows specifying only those characters which are to be shown
  491.           % the chars can be specified inside of quotes("c") or as a number(23)
  492. def OK expr x=known wanted[byte x] enddef;
  493.  %  let iff=always_iff;               % allows testing of all chars in the file
  494.  
  495. %*****
  496. % This allows adjustments to left and right sidebearings of characters, 
  497. %   so that the space in which the character sits can be different from
  498. %   the space in which the reference points for the character are given.
  499.  
  500. letter_fit#:=letter_fit:=0;
  501. def adjust(expr left_adjustment,right_adjustment) =
  502.    l:=-round(left_adjustment*hppp)-letter_fit;
  503.    interim xoffset:=-l;
  504.    charwd:=charwd+2letter_fit#+left_adjustment+right_adjustment;
  505.    r:=l+round(charwd*hppp);
  506.    w:=r-round(right_adjustment*hppp)-letter_fit; 
  507.  enddef;
  508.            
  509. %*****
  510.  
  511. % Changes <penpos> to <pos> and makes <multpos> for multiple reference positions
  512. %   with the same length and angle arguments
  513.  
  514. vardef pos@#(expr b,d) =
  515.  (x@#r-x@#l,y@#r-y@#l)=(b,0)rotated d;x@#=.5(x@#l+x@#r);y@#=.5(y@#l+y@#r)enddef;
  516. vardef multpos(text t)(expr b,d)=forsuffixes $=t:pos$(b,d); endfor enddef;
  517.  
  518. %*****
  519.  
  520. % A takeoff on flex, allows softening of paths if softpath is true.
  521. % This takes a list of points and softens the path between the straight
  522. %   lines connecting these points; a <point> or <path> must follow this
  523. %   macro, i.e., not a <pathjoin>.
  524.  
  525. def soften(text t)=                                     % t is a list of pairs
  526.  hide(n_:=0; for z=t: z_[incr n_]:=z; endfor;)           
  527.  if softpath:
  528.     --z_1)for k=2 upto n_:softjoin(z_[k-1]--z_[k]) endfor softjoin(z_[n_]--
  529.     else: --z_1 for k=2 upto n_-1: --z_[k] endfor --z_[n_]-- fi
  530. enddef;
  531. newinternal n_; pair z_[],dz_;
  532.  
  533. %*****
  534.  
  535.  
  536. %*****MISCELLANEOUS 
  537.  
  538. %**** fitbasis *****
  539. % If the basis for figuring the sidebearings or fitting has not been set
  540. % to 0 by the fixed_pitch_characters macro, then this gives values to the
  541. % upper and lower case <fitbasis>
  542.  
  543. def makeknown(text t)(expr value)=
  544.   forsuffixes $=t:if unknown $:$=value;fi endfor enddef;
  545.  
  546. %***** booleans
  547.  
  548. % These macros shorten the code
  549. def bool(text t)=boolean t; t enddef;
  550. def save_bool(text t)=save t;bool(t) enddef;
  551. def save_pair(text t)=save t;pair t; t enddef;
  552. def save_pairs(text t)=save t;pair t[]; enddef;
  553. def save_num(text t)=save t;t enddef;
  554.  
  555. % The condition macro localizes a boolean and gives it a true or false value
  556.  
  557. def condition(text t)suffix $$=
  558.   save_bool(t):=if(str$$="t"):true else:false; fi enddef;
  559.  
  560. %*****
  561.  
  562. % The softenit macro softens the join for two paths that are always to 
  563. %   have some softness
  564.  
  565. vardef softenit(expr path_one,path_two)=
  566.   save x,y,t;
  567.   (t1,t2)=path_one intersectiontimes reverse path_two;
  568.   z1=path_one intersectionpoint reverse path_two;
  569.   (subpath(0,t1)of path_one--z1)softjoin(z1--subpath(t2,0)of reverse path_two)
  570. enddef;
  571.  
  572. %***** 
  573.  
  574. % The define_minimums macro makes minimum stroke amount of one pixel
  575. def define_minimums(text t)=forsuffixes $=t: $:=max($,minimum_linethickness); 
  576.   endfor enddef; 
  577.  
  578. %*****
  579. % For turning off overshoots when the resolution is too low
  580. def lowres_fix(text t)=forsuffixes $=t: $:=0; endfor enddef; 
  581. %*****
  582.  
  583. % The fixed_pt macro increases the length of the stem measurement dependent
  584. %   on the obliqueness to maintain stem widths 
  585. % Used only in global bowlstem/stem/thin_stem specs
  586.  
  587. if unknown scale_factor:scale_factor=1; fi 
  588. def fixed_pt=(scale_factor*1/(pt#*cosd oblique)) enddef; 
  589.  
  590. %*****
  591.  
  592. % In the inlimit macro, the first <text> argument gives the value, 
  593. %   and places this value between the <expr> arguments
  594. % The lower and upper bound values are just recommended values thought
  595. %   to maintain "reasonable" shapes
  596. vardef inlimit(text amt)(expr lowerlimit,upperlimit)=save this;
  597.  this:=max(amt,lowerlimit); this:=min(this,upperlimit);this
  598. enddef;
  599.  
  600. % The min_limit macro maintains a minimum limit
  601. def min_limit(text this)(expr limit)=if this>limit:save this;this=limit;fi 
  602. enddef;
  603.  
  604. %*****
  605.  
  606. % Gives value to the <sign> used in terminalserif def
  607. def sign(expr a)=if a<=0:0 else:1 fi enddef;
  608.  
  609. %*****
  610.  
  611. % The onaline macro allows thinking that a point be on a particular line;
  612. %  an x or y value must be supplemented
  613.  
  614. vardef onaline(suffix a,b)(text t)=forsuffixes $=t:z$=whatever[z.a,z.b]; endfor
  615.  enddef;
  616.  
  617. %*****
  618. % The good_x_for macro gives reference points horizontal placement, 
  619. %   and moves them appropriately, according to vertical height and obliqueness
  620.  
  621. vardef good_x_for(text t)(expr leftpoint,rightpoint,amt)suffix$=
  622.   z1$=(xpart leftpoint,y.t-ypart leftpoint)//; 
  623.   z2$=(xpart rightpoint,y.t-ypart rightpoint)//;
  624.   x.t=amt[x1$,x2$];
  625. enddef;
  626.  
  627. %*****
  628.  
  629. % The constant_angle macro keeps a constant angle so that the thickness
  630. %  of the line can remain constant as the line may change, e.g., as width,
  631. %  obliqueness changes.
  632. % The stem value should be zero if the reference points are on the same
  633. %  side of the stem, and the value of the stem otherwise.
  634. % The suffix lr is used when the reference points are diagonally opposite
  635. %  each other and the top_pt is on the left of the stem
  636. %  and the bot_pt on the right.
  637. % This could probably be made more efficient, but it works as is... *** FIX
  638.  
  639. vardef constant_angle(expr top_pt,bot_pt,stem)suffix $=
  640.   save theta;   
  641.   theta=if str$="lr":-else:+fi (angle(length(top_pt-bot_pt) +-+ stem,stem)); 
  642.   angle(top_pt-bot_pt)+theta-90
  643. enddef;
  644.  
  645. %*****
  646.  
  647. % The notch macro makes an indentation to compensate for filling in at junctures
  648. % Variation in the length and width or thickness of the cut can be specified
  649. % Ideally one might tailor the length of the cut dependent on the angle 
  650. % of the two stems at the juncture, however, here they are all considered 
  651. % together
  652. % The notch macros:upnotch,downnotch,leftnotch,rightnotch all assume
  653. % A three point counterclockwise path with the notching occuring at the 
  654. % middle point; the points connect as straight lines and the notching 
  655. % begins at a point .5 of the way from the endpoints to the apex
  656.  
  657. vardef notch@#(expr apath,notch_direction,notch_length)=
  658.  save a; def a=(max(notch_length,eps),0)rotated notch_direction; enddef;
  659.  z0=point 1 of apath; z2=z1+a; z3=z6+a; z4=z5+a; z6=.5[z1,z5];
  660.  if str@#="r":reverse fi
  661.   (point 0 of apath--point .5 of apath
  662.    if nonotch:--z0--else: ..controls z1..z2--z4..controls z5.. fi
  663.   point 1.5 of apath--point 2 of apath)
  664. enddef; 
  665.  
  666. vardef rightnotch@#(expr one,n_dir,n_l)suffix $=
  667.  save x,y,a; def a(expr n)=(n*notch_width,0)rotated(n_dir+90); enddef;
  668.  if center_notch:          z6=z0; z1=z0-a(.5);
  669.    elseif str$="etchup":   z1=z0; z5=z0+a(1); 
  670.    elseif str$="etchdown": z5=z0; z1=z0-a(1);else:z6=z0; z1=z0-a(.5); fi
  671.  notch@#(one,n_dir,n_l) enddef;
  672. vardef leftnotch@#(expr one,n_dir,n_l)suffix $=
  673.  save x,y,a; def a(expr n)=(n*notch_width,0)rotated(n_dir-90); enddef;
  674.  if center_notch:          z6=z0; z5=z0-a(.5);
  675.    elseif str$="etchup":   z5=z0; z1=z0+a(1); 
  676.    elseif str$="etchdown": z1=z0; z5=z0-a(1);else:z6=z0; z5=z0-a(.5); fi
  677.  notch@#(one,n_dir,n_l) enddef;
  678. vardef upnotch@#(expr one,n_dir,n_l)suffix $=
  679.  save x,y,a; def a(expr n)=(n*notch_width,0)rotated(n_dir-90); enddef;
  680.  if center_notch:          z6=z0; z1=z0+a(.5);
  681.    elseif str$="etchleft": z1=z0; z5=z0-a(1);
  682.    elseif str$="etchright":z5=z0; z1=z0+a(1); else:z6=z0; z1=z0+a(.5); fi
  683.  notch@#(one,n_dir,n_l) enddef;
  684. vardef downnotch@#(expr one,n_dir,n_l)suffix $=
  685.  save x,y,a; def a(expr n)=(n*notch_width,0)rotated(n_dir+90); enddef;
  686.  if center_notch:          z6=z0; z5=z0+a(.5);
  687.    elseif str$="etchleft": z5=z0; z1=z0-a(1);
  688.    elseif str$="etchright":z1=z0; z5=z0+a(1); else:z6=z0; z5=z0+a(.5); fi
  689.  notch@#(one,n_dir,n_l) enddef;
  690.  
  691. %*****
  692.  
  693. %*****
  694.  
  695. % The fixed_pitch_characters macro takes a true/false(or otherwise)
  696. %   and number of characters_per_inch arguments. 
  697. % This macro sets the often used <mono> value and other values for 
  698. %   single pitch, where all characters have the same width.
  699. % Note that a slight alteration made to mono# will allow
  700. %   the character width to be specified arbitrarily, e.g., setting
  701. %   mono#:=10.7pt# makes a single pitch width of 10.7 points.
  702.  
  703. def fixed_pitch_characters(text t)(expr characters_per_inch)=
  704.  boolean narrow_condition;       % are characters especially narrow?
  705.  boolean singlepitch;            % affects character shapes for ijlwIJMWO0
  706.  if t=true:mono#:=(72.27/characters_per_inch)*pt#;
  707.            width#:=0;
  708.            fitbasis.lc#:=fitbasis.uc#:=0; 
  709.            singlepitch:=true; 
  710.       else:mono#:=0;
  711.            singlepitch:=false;      fi
  712.  define_pixels(mono,width);
  713.  narrow_condition:=if (mono<>0)and(characters_per_inch>12):true else:false fi;
  714. enddef;
  715.  
  716. %*****
  717.  
  718. vardef testing_codes=
  719.   % There are a number of alternate characters. The "alt[]" scheme gives these
  720.   % alternate characters a different code number than the one they would 
  721.   % normally have, if used, for the purpose of testing.  
  722.  
  723.   if test_all_characters:
  724.      alt0:=if a_full_bowl:128 else:0 fi;           % characters: a
  725.      alt1:=if g_full_bowl:128 else:0 fi;           % characters: g
  726.      alt2:=if spur:0 else:128 fi;                  % characters: G,b,q (a,g)
  727.      alt3:=if like_lowercase:128 else:0 fi;        % characters: U
  728.      alt4:=if flat_diagonal_endings:0 else:128 fi; % characters: v,w,x,y,V,W,X
  729.      alt5:=if beveled_join:128 else:0 fi;          % characters: R,K,k
  730.      alt6:=if open_tail:0 else:128 fi;             % characters: 3,5,6,9
  731.      alt7:=if diagonal_three:0 else:128 fi;        % characters: 3
  732.      alt8:=if inflection_two:0 else:128 fi;        % characters: 2
  733.      alt9:=if G_spur:128 else:0 fi;                % characters: G
  734.      alt10:=if open_four:0 else:128 fi;            % characters: 4
  735.  
  736.    else:alt0:=alt1:=alt2:=alt3:=alt4:=alt5:=alt6:=alt7:=alt8:=alt9:=alt10:=0; fi
  737. enddef;
  738.  
  739. %*******************************
  740. makeknown(minimum_linethickness)(1);
  741.  
  742.  
  743. def vpix(text t)(text tt)= t:=tt; t:=vround(tt.#*hppp); enddef;   % whole v pix
  744. def hpix(text t)(text tt)= t:=tt; t:=hround(tt.#*hppp); enddef;   % whole h pix
  745.  
  746.  
  747. def define_pixels(text t) =
  748.  forsuffixes $=t: $:=$.#*hppp; endfor enddef;
  749. def define_whole_pixels(text t) =
  750.  forsuffixes $=t: $:=hround($.#*hppp); endfor enddef;
  751. def define_whole_vertical_pixels(text t) =
  752.  forsuffixes $=t: $:=vround($.#*hppp); endfor enddef;
  753. def define_good_x_pixels(text t) =
  754.  forsuffixes $=t: $:=good.x($.#*hppp); endfor enddef;
  755. def define_good_y_pixels(text t) =
  756.  forsuffixes $=t: $:=good.y($.#*hppp); endfor enddef;
  757. def define_blacker_pixels(text t) =
  758.  forsuffixes $=t: $:=$.#*hppp+blacker; endfor enddef;
  759. def define_whole_blacker_pixels(text t) =
  760.  forsuffixes $=t: $:=hround($.#*hppp+blacker);
  761.   if $<=0: $:=1; fi endfor enddef;
  762. def define_whole_vertical_blacker_pixels(text t) =
  763.  forsuffixes $=t: $:=vround($.#*hppp+blacker);
  764.   if $<=0: $:=1_o_; fi endfor enddef;
  765. def define_corrected_pixels(text t) =
  766.  forsuffixes $=t: $:=vround($.#*hppp*o_correction)+eps; endfor enddef;
  767. def define_horizontal_corrected_pixels(text t) =
  768.  forsuffixes $=t: $:=hround($.#*hppp*o_correction)+eps; endfor enddef;
  769.  
  770.  
  771.